#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File: redis.py
# @Author: lotus163
# @Date: 2022/10/28
from datetime import datetime
from typing import List, Tuple

from aioredis import Redis
from loguru import logger

from backend.crud import SysConfigDao, DictTypeDao, DictDataDao, UserDao
from backend.schemas import SysDictDataSch, LoginUserSch, UserOnlineSch, LoginInforSch
from backend.schemas.system.sys_dict import RedisDictDataSch
from backend.service.system.scope import DataScopeService
from backend.service.system.user import UserService


def get_login_tokens_key(uuid: str) -> str:
    """# 登录用户 redis key"""
    return "login_tokens:" + uuid


def get_config_key(configKey: str) -> str:
    """# 参数管理 cache key"""
    return "sys_config:" + configKey


def get_dict_type_key(dictTpye: str) -> str:
    """# 参数管理 cache key"""
    return "sys_dict:" + dictTpye


def get_captcha_codes_key(uuid: str) -> str:
    """# 参数管理 cache key"""
    return "captcha_codes:" + uuid


class MyRedis(Redis):
    """ 继承Redis,并添加自己的方法 """

    def get_cmdstat_list(self, cmdstat_dict):
        cmdstat_list = []
        for key, value in cmdstat_dict.items():
            name = key.split("_")[-1]
            val = str(value["calls"])
            cmdstat_list.append({"name": name, "value": val})
        return cmdstat_list

    def get_cache_name_infos(self):
        return [{"cacheName": "login_tokens:", "cacheKey": "", "cacheValue": "", "remark": "用户信息"},
                {"cacheName": "sys_config:", "cacheKey": "", "cacheValue": "", "remark": "配置信息"},
                {"cacheName": "sys_dict:", "cacheKey": "", "cacheValue": "", "remark": "数据字典"},
                {"cacheName": "captcha_codes:", "cacheKey": "", "cacheValue": "", "remark": "验证码"},
                {"cacheName": "repeat_submit:", "cacheKey": "", "cacheValue": "", "remark": "防重提交"},
                {"cacheName": "rate_limit:", "cacheKey": "", "cacheValue": "", "remark": "限流处理"},
                {"cacheName": "pwd_err_cnt:", "cacheKey": "", "cacheValue": "", "remark": "密码错误次数"}]

    async def loading_config_cache(self):
        """载入config到redis"""
        # 从数据库读取sys_config
        configs = await SysConfigDao.get_list_db()
        # 循环写入redis
        for config in configs:
            await self.set(get_config_key(config.configKey), config.configValue)
        logger.debug("redis存储sys_config成功。")

    async def loading_dict_cache(self):
        """载入config到redis"""
        # 从数据库读取sys_config
        dict_types_db = await DictTypeDao.get_list_db()
        # 循环写入redis
        for dict_type_db in dict_types_db:
            key = get_dict_type_key(dict_type_db.dictType)
            dict_datas_sch: List[SysDictDataSch] = await DictDataDao.get_list_sch(dictType=dict_type_db.dictType)
            await self.set(key, RedisDictDataSch(__root__=dict_datas_sch).json())
        logger.debug("redis存储sys_dict成功。")

    async def get_dict_cache(self, dict_type: str) -> List[SysDictDataSch]:
        """获取dict的缓存信息"""
        value = await self.get(get_dict_type_key(dict_type))
        dict_type_datas_sch = RedisDictDataSch.parse_raw(value)
        return dict_type_datas_sch.__root__

    async def save_login_tokens(self, login_info_sch: LoginInforSch,token:str,expireTime:int,uuid:str):
        """保存用户登录信息"""
        user_db = await UserDao.get_db_or_none(userName=login_info_sch.userName)
        # 获取完整的user_all_sch
        user_all_sch = await UserService().get_user_all_sch_by_db(user_db)
        data_scope = await DataScopeService().get_scope_sch(user_all_sch)
        login_user_sch: LoginUserSch = LoginUserSch(
            login_infor=login_info_sch,
            user=user_all_sch,
            data_scope=data_scope,
            userId=user_all_sch.userId,
            token=token,
            uuid=uuid,
            expireTime=expireTime,
        )
        # 过期时间
        ex = expireTime-int(datetime.utcnow().timestamp())
        await self.set(get_login_tokens_key(uuid), login_user_sch.json(exclude_none=True),ex=ex)

    async def update_login_tokens(self,login_user_sch:LoginUserSch):
        await self.save_login_tokens(login_user_sch.login_infor,
                               login_user_sch.token,
                               login_user_sch.expireTime,
                               login_user_sch.uuid)


    async def delete_login_tokens(self, uuid: str):
        """删除用户登录信息"""
        await self.delete(get_login_tokens_key(uuid))



    async def get_users_online_sch(self) -> Tuple:
        """获取在线用户"""
        users_json = []
        async for key in self.scan_iter("login_tokens:*"):
            users_json.append(await self.get(key))
        total = len(users_json)
        users_online_sch = []
        for user_json in users_json:
            login_user_temp: LoginUserSch = LoginUserSch.parse_raw(user_json)
            user_online_sch: UserOnlineSch = UserOnlineSch(
                ipaddr=login_user_temp.login_infor.ipaddr,
                loginLocation=login_user_temp.login_infor.loginLocation,
                browser=login_user_temp.login_infor.browser,
                os=login_user_temp.login_infor.os,
                deptName=login_user_temp.user.dept.deptName,
                loginTime=login_user_temp.login_infor.loginTime,
                userName=login_user_temp.login_infor.userName,
                tokenId=login_user_temp.uuid
            )
            users_online_sch.append(user_online_sch)
        return total, users_online_sch
